import { useUserStore } from '@/store'
import { qs } from '@/utils'
import { platform } from '@/utils/platform'

export type CustomRequestOptions = UniApp.RequestOptions & {
  query?: Record<string, any>
  /** 出错时是否隐藏错误提示 */
  hideErrorToast?: boolean
  /** 是否是加密接口 */
  encrypt?: boolean
  onlyData?: boolean
  headers?: { _isRefreshToken?: boolean }
  contentType?: 'application/json' | 'application/x-www-form-urlencoded'
  httpConfig?: Omit<HttpConfig, 'loginUrl'>
  /** 权重最高，会直接打印 resJosn */
  debug?: boolean
  debugFormat?: 'obj' | 'json'
  /** 调试 输出结果的json */
  debugResponse?: boolean
  /** 调试 传入的 options */
  debugOptions?: boolean
}

export interface SetupRequestUrlType {
  // 请求地址，不包含服务器
  url: string
  // 是否去掉前缀，如：/cms/foo -> /foo
  removePrefix?: boolean
  // 新的urlMap，可以适配 服务器动态获取的情况
  urlMap?: Record<string, any>
}

const timeout = 30000 // 请求超时时间
const baseUrl = (import.meta as any).env.VITE_SERVER_BASEURL // 请求基础路径

// 对接多个后端服务
// 这里配置了 开发跨域问题  env 那边的多proxy还是要配置的
const defaultUrlMap = {
  main: baseUrl,
}

function setupRequestUrl({ url, removePrefix, urlMap }: SetupRequestUrlType = { url: '' }) {
  // url: `/cms/foo`, // 看这里，前缀不用！！！
  if (typeof url !== 'string') {
    throw new TypeError('输入必须是字符串')
  }
  const resUrlMap = urlMap ?? defaultUrlMap
  const findKey = Object.keys(resUrlMap).find(key => url.startsWith(`/${key}/`))
  const newUrl = removePrefix ? url.replace(`/${findKey}/`, '/') : url
  return findKey ? `${resUrlMap[findKey]}${newUrl}` : `${resUrlMap.main}${newUrl}`
}

// 拦截器配置
const httpInterceptor = {
  // 请求前的拦截
  invoke(options: CustomRequestOptions) {
    options.debugFormat = options.debugFormat ?? 'obj'
    // 1. 设置请求路径
    if (!options.url.includes('//')) {
      // 非完整路径，补全基础路径
      // 完整路径：http://localhost:8080/api/user/login
      // 非完整路径：api/user/loginApi
      // #ifdef H5
      if (JSON.parse(__VITE_APP_PROXY__)) {
        // 啥都不需要做 主要是跨域问题
        // console.log(setupRequestUrl({
        //   url: options.url,
        //   urlMap: {
        //     main: 'http://baseUrl',
        //   },
        // }))
      }
      else {
        options.url = setupRequestUrl({
          url: options.url,
        })
      }
      // #endif
      // 非H5正常拼接
      // #ifndef H5
      options.url = setupRequestUrl({
        url: options.url,
      })
      // #endif
      // TIPS: 如果需要对接多个后端服务，也可以在这里处理，拼接成所需要的地址
    }
    // 2. query 参数处理
    if (options.query) {
      // qs.stringify() 方法将一个 JavaScript 对象或数组转换为一个查询字符串
      // 比如： { name: 'tom', age: 18 } 转换成 name=tom&age=18
      const query = qs.stringify(options.query)
      options.url += (options.url.includes('?') ? `&` : `?`) + query
    }
    // 3. 请求超时时间设置
    options.timeout = timeout
    // 4. 定义请求返回数据的格式（设为 json，会尝试对返回的数据做一次 JSON.parse）
    options.dataType = 'json'
    // #ifndef MP-WEIXIN
    options.responseType = 'json'
    // #endif
    // 5. 添加请求头标识，可以告诉后台是小程序端发起的请求
    const contentType = options.contentType || 'application/json'
    if (contentType === 'application/x-www-form-urlencoded') {
      options.data = qs.stringify(options.data || {})
    }

    options.header = {
      // platform: 'mini-program', 比如 platform 字段可以告诉后台是小程序端发起的请求
      platform,
      'Content-Type': contentType.toLowerCase().includes('utf-8') ? `${contentType}; charset=UTF-8` : contentType,
      ...options.header,
    }
    // 6. 添加 token 请求头标识
    const store = useUserStore()
    const { accessToken = '' } = store.userInfo || {}
    if (accessToken) {
      // console.log(__VITE_TOKEN_PREFIX__)
      const prefix = __VITE_TOKEN_PREFIX__ || ''
      options.header.Authorization = prefix ? `${prefix} ${accessToken}` : accessToken
    }
    return options
  },
}

export const requestInterceptor = {
  install() {
    // 拦截 request 请求
    uni.addInterceptor('request', httpInterceptor)
  },
}
